package cn.com.cpic.insurance.rulecheck.core.expression;

import cn.com.cpic.insurance.rulecheck.core.Context;
import cn.com.cpic.insurance.rulecheck.core.exception.OperateException;

/**
 * 二元表达式
 * 
 * @author 代波
 * @since 2011-8-14
 * @param <T> 表达式的输出结果类型
 * @param <V> 表达式的输入参数类型
 */
public abstract class BinaryExpression<T, V> implements Expression<T> {
	private static final long serialVersionUID = 3750030111252661387L;

	private final Expression<V> lhs;
	private final Expression<V> rhs;

	public BinaryExpression(Expression<V> lhs, Expression<V> rhs) {
		super();
		this.lhs = lhs;
		this.rhs = rhs;
	}

	public final T operate(Context context) throws OperateException {
		V lValue = lhs.operate(context);
		V rValue = rhs.operate(context);
		boolean typeMismatch;
		if ((typeMismatch = (lValue.getClass() != rValue.getClass()))
				&& !canOperateWhenTypeMismatch(context, lValue, rValue)) {
			throw new IllegalArgumentException("二元操作两边的值类型不一致：左边[" + lValue.getClass() + "]；右边[" + rValue.getClass()
					+ "]");
		}
		return operate(context, lValue, rValue, typeMismatch);
	}

	/**
	 * 获得操作结果
	 * 
	 * @param context 上下文
	 * @param lValue 左表达式的值
	 * @param rValue 右表达式的值
	 * @param typeMismatch 执行此操作时，值类型是否一致，true为不一致，false为一致
	 * @return 操作的结果
	 */
	protected abstract T operate(Context context, V lValue, V rValue, boolean typeMismatch);

	/**
	 * 当二元操作符两边的值类型不一致时，通过调用此方法来识别是否支持不一致的值类型的进一步操作
	 * 
	 * @param context 上下文
	 * @param lValue 左表达式的值
	 * @param rValue 右表达式的值
	 * @return 是否支持不一致的值类型的进一步操作
	 */
	protected abstract boolean canOperateWhenTypeMismatch(Context context, V lValue, V rValue);
}
